package org.domeos.framework.api.service.deployment.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.domeos.basemodel.HttpResponseTemp;
import org.domeos.basemodel.ResultStat;
import org.domeos.exception.DeploymentEventException;
import org.domeos.framework.api.biz.cluster.ClusterBiz;
import org.domeos.framework.api.biz.collection.CollectionBiz;
import org.domeos.framework.api.biz.configuration.ConfigurationBiz;
import org.domeos.framework.api.biz.deployment.DeployCollectionBiz;
import org.domeos.framework.api.biz.deployment.DeploymentBiz;
import org.domeos.framework.api.biz.deployment.VersionBiz;
import org.domeos.framework.api.biz.global.GlobalBiz;
import org.domeos.framework.api.biz.storage.StorageBiz;
import org.domeos.framework.api.consolemodel.deployment.ContainerConsole;
import org.domeos.framework.api.consolemodel.deployment.ContainerDraft;
import org.domeos.framework.api.consolemodel.deployment.EnvDraft;
import org.domeos.framework.api.consolemodel.deployment.VersionDraft;
import org.domeos.framework.api.consolemodel.deployment.VersionInfo;
import org.domeos.framework.api.consolemodel.deployment.VersionString;
import org.domeos.framework.api.consolemodel.deployment.VolumeDraft;
import org.domeos.framework.api.consolemodel.deployment.VolumeMountConsole;
import org.domeos.framework.api.consolemodel.deployment.VolumeMountDraft;
import org.domeos.framework.api.controller.exception.ApiException;
import org.domeos.framework.api.controller.exception.PermitException;
import org.domeos.framework.api.model.auth.User;
import org.domeos.framework.api.model.cluster.Cluster;
import org.domeos.framework.api.model.collection.CollectionResourceMap;
import org.domeos.framework.api.model.collection.related.ResourceType;
import org.domeos.framework.api.model.configuration.Configuration;
import org.domeos.framework.api.model.deployment.DeployCollection;
import org.domeos.framework.api.model.deployment.Deployment;
import org.domeos.framework.api.model.deployment.Version;
import org.domeos.framework.api.model.deployment.related.CustomLabel;
import org.domeos.framework.api.model.deployment.related.DeploymentStatus;
import org.domeos.framework.api.model.deployment.related.VersionType;
import org.domeos.framework.api.model.deployment.related.VolumeConfigMap;
import org.domeos.framework.api.model.deployment.related.VolumePVC;
import org.domeos.framework.api.model.deployment.related.VolumeType;
import org.domeos.framework.api.model.operation.OperationType;
import org.domeos.framework.api.model.storage.Storage;
import org.domeos.framework.api.model.storage.VolumeDeployMap;
import org.domeos.framework.api.service.auth.UserService;
import org.domeos.framework.api.service.deployment.VersionService;
import org.domeos.framework.api.service.storage.StorageService;
import org.domeos.framework.engine.AuthUtil;
import org.domeos.framework.engine.ClusterRuntimeDriver;
import org.domeos.framework.engine.RuntimeDriver;
import org.domeos.framework.engine.coderepo.ReflectFactory;
import org.domeos.framework.engine.k8s.handler.DeployResourceHandler;
import org.domeos.global.CurrentThreadInfo;
import org.domeos.global.GlobalConstant;
import org.domeos.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 */
@Service
public class VersionServiceImpl implements VersionService {
	
	@Autowired
    GlobalBiz globalBiz;

    @Autowired
    VersionBiz versionBiz;

    @Autowired
    DeploymentBiz deploymentBiz;

    @Autowired
    ClusterBiz clusterBiz;

    @Autowired
    ConfigurationBiz configurationBiz;
    
    @Autowired
    StorageBiz storageBiz;
    
    @Autowired
    UserService userService;
    
    @Autowired
    StorageService storageService;
    
    @Autowired
    CollectionBiz collectionBiz;
    
    @Autowired
    DeployCollectionBiz deployCollectionBiz;
    
    @Override
    public HttpResponseTemp<?> sreCreateVersion(VersionDraft versionDraft, int deployId) throws Exception{
    	versionDraft = nfsFilter(versionDraft, deployId);
    	if (versionDraft == null) {
    		return ResultStat.PARAM_ERROR.wrap("deployment is not exist");
    	}
        versionDraft.convertToVersion();
        String versionLegality = versionDraft.checkLegality();
        if (!StringUtils.isBlank(versionLegality)) {
        	return ResultStat.PARAM_ERROR.wrap(versionLegality);
        }
        
        //增加超分超卖配置
        double cpupercent = globalBiz.getCpuPercent();
        double memorypercent = globalBiz.getMemoryPercent();
        for(ContainerDraft cd:versionDraft.getContainerDrafts()) {
        	cd.setCpuRequest(cd.getCpuRequest() * cpupercent);
        	cd.setMemRequest(cd.getMemRequest() * memorypercent);
        }
        
        long versionId;
        try {
            Deployment deployment = deploymentBiz.getDeployment(deployId);
            if (deployment == null) {
            	return ResultStat.PARAM_ERROR.wrap("deployment is not exist");
            }
            Cluster cluster = clusterBiz.getClusterById(deployment.getClusterId());
            if (cluster == null) {
            	return ResultStat.PARAM_ERROR.wrap("CLUSTER is not exist");
            }
          //更新增加唯一label
            CollectionResourceMap crm = collectionBiz.getResourceByResourceIdAndResourceType(deployId, ResourceType.DEPLOY);
            addlabeltoversion(versionDraft,crm.getCollectionId());
            
            versionId = versionBiz.insertVersionWithLogCollect(versionDraft, cluster);
        } catch (Exception e) {
            versionBiz.removeById(GlobalConstant.VERSION_TABLE_NAME, versionDraft.getId());
            return ResultStat.PARAM_ERROR.wrap(e.getMessage());
        }
        
        // add volume_deploy_map
        for(VolumeDraft vd : versionDraft.getVolumeDrafts()) {
    		if ("PERSISTENTVOLUMECLAIM".equals(vd.getVolumeType().name())) {
    			String storageName = vd.getVolumePVC().getClaimName().split("-pvc")[0];
    			Storage storage = storageBiz.getStorageByName(storageName);
    			VolumeDeployMap volumeDeployMap = new VolumeDeployMap();
    			volumeDeployMap.setDeployId(deployId);
    			volumeDeployMap.setVersionId(versionDraft.getId());
    			volumeDeployMap.setVolumeId(storage.getId());
    			volumeDeployMap.setCreateTime(System.currentTimeMillis());
    			storageBiz.addVolumeVersionMount(volumeDeployMap);
    		}
        }
        
        return ResultStat.OK.wrap(versionId);

    }
    
    private VersionDraft nfsFilter(VersionDraft versionDraft, int deployId) {
    	Deployment deployment = deploymentBiz.getDeployment(deployId);
        if (deployment == null) {
        	return null;
        }
		User user =  userService.getUser(versionDraft.getUserId());
		for(ContainerConsole containerConsole : versionDraft.getContainerConsoles()) {
			if(CollectionUtils.isNotEmpty(containerConsole.getVolumeMountConsoles())) {
				for(VolumeMountConsole volumeMountConsole : containerConsole.getVolumeMountConsoles()) {
					if(volumeMountConsole.getVolumeType().equals(VolumeType.NFS)) {
						List<Storage> storages = storageBiz.getStorageByPathAndServer(volumeMountConsole.getNfs().getPath(), volumeMountConsole.getNfs().getServer());
						Storage storage;
						if(storages == null || storages.size() == 0) {
							// create storage
							storage = new Storage();
							storage.setClusterId(deployment.getClusterId());
							storage.setNamespace(deployment.getNamespace());
							storage.setName(deployment.getName() + "-version" + String.valueOf(versionBiz.getNextVersion(deployId)));
							storage.setPath(volumeMountConsole.getNfs().getPath());
							storage.setServer(volumeMountConsole.getNfs().getServer());
							storage.setType("nfs");
							storage.setCreateTime(System.currentTimeMillis());
							storage.setCreatorId(versionDraft.getUserId());
							storageService.sreSetStorage(user, storage);
						} else {
							storage = storages.get(0);
						}
						volumeMountConsole.setVolumeType(VolumeType.PERSISTENTVOLUMECLAIM);
						VolumePVC volumePVC = new VolumePVC();
						volumePVC.setClaimName(storage.getName() + "-pvc");
						volumePVC.setReadOnly(volumeMountConsole.isReadonly());
						volumeMountConsole.setVolumePVC(volumePVC);
					}
				}
			}
		}
		//设置收集日志
        Set<String> path = null;
        if(CollectionUtils.isNotEmpty(versionDraft.getContainerConsoles())){
        	for(ContainerConsole console : versionDraft.getContainerConsoles()){
        		path = new HashSet<String>();
        		if(CollectionUtils.isNotEmpty(console.getEnvs())){
        			for(EnvDraft envDraft : console.getEnvs()){
        				if(envDraft.getValue().startsWith("/")){
        					String[] logsPath = StringUtils.split(envDraft.getValue(),",");
        		        	for(int i = 0 ; i < logsPath.length ; i ++){
        		        		path.add(new File(logsPath[i]).getParent());
        		        	}
        				}
        			}
        		}
        		if(CollectionUtils.isNotEmpty(path)){
                	List<VolumeMountConsole> mountConsoles = new ArrayList<VolumeMountConsole>();
                	List<VolumeMountDraft> mountDrafts = new ArrayList<VolumeMountDraft>();
                	Iterator<String> i = path.iterator();
                	int index = 0;
                    while(i.hasNext()){
                    	String p = i.next();
                    	VolumeMountConsole volumeMountConsole = new VolumeMountConsole();
                		volumeMountConsole.setName("log-" + index);
                		volumeMountConsole.setContainerPath(p);
                		volumeMountConsole.setVolumeType(VolumeType.EMPTYDIR);
                		mountConsoles.add(volumeMountConsole);
                    	
                    	VolumeMountDraft volumeMountDraft = new VolumeMountDraft();
                		volumeMountDraft.setMountPath(p);
                		volumeMountDraft.setName("log-" + index);
                		mountDrafts.add(volumeMountDraft);
                		
                		index ++;
                    }  
                	console.setVolumeMountConsoles(mountConsoles);
                	console.setVolumeMountDrafts(mountDrafts);
                }
        	}
            
        }
		return versionDraft;
	}
    
    public void addlabeltoversion(Version version,int deploycid) {
        //获取lbc  name,并通过treeid、deploylc、deploymentname拼凑唯一label
        Deployment deployment = deploymentBiz.getDeployment(version.getDeployId());
        DeployCollection deployc = deployCollectionBiz.getDeployCollectionByID(deploycid);
        //唯一label
        String unique =  deployc.getName() +deployment.getName() + String.valueOf(deployc.getTreeId());
        //添加到version中
        CustomLabel cl = new CustomLabel();
        cl.setKey("unique");
        cl.setValue(unique);
        cl.setDescription("bind service");
        
        if(CollectionUtils.isNotEmpty(version.getCustomLabels())) {
        	version.getCustomLabels().add(cl);
        }else {
        	List<CustomLabel> customLabels = new ArrayList<CustomLabel>();
        	customLabels.add(cl);
        	version.setCustomLabels(customLabels);
        }
    }

    @Override
    public Long createVersion(VersionDraft versionDraft, int deployId) throws Exception {
        checkDeployPermit(deployId, OperationType.MODIFY);
        versionDraft.convertToVersion();
        String versionLegality = versionDraft.checkLegality();
        if (!StringUtils.isBlank(versionLegality)) {
            throw ApiException.wrapMessage(ResultStat.DEPLOYMENT_NOT_LEGAL, versionLegality);
        }
		//增加超分超卖配置
        double cpupercent = globalBiz.getCpuPercent();
        double memorypercent = globalBiz.getMemoryPercent();
        for(ContainerDraft cd:versionDraft.getContainerDrafts()) {
        	//页面只传了limits参数，首先更新requests为limits的值,然后再乘参数
        	cd.setCpuRequest(cd.getCpu());
        	cd.setMemRequest(cd.getMem());
        	cd.setCpuRequest(cd.getCpuRequest() * cpupercent);
        	cd.setMemRequest(cd.getMemRequest() * memorypercent);
        }
        
        
        long versionId;
        try {
            Deployment deployment = deploymentBiz.getDeployment(deployId);
            if (deployment == null) {
                throw ApiException.wrapResultStat(ResultStat.DEPLOYMENT_NOT_EXIST);
            }
            Cluster cluster = clusterBiz.getClusterById(deployment.getClusterId());
            if (cluster == null) {
                throw ApiException.wrapResultStat(ResultStat.CLUSTER_NOT_EXIST);
            }
            //更新增加唯一label
            CollectionResourceMap crm = collectionBiz.getResourceByResourceIdAndResourceType(deployId, ResourceType.DEPLOY);
            if(crm != null){
            	addlabeltoversion(versionDraft,crm.getCollectionId());
            }
            versionId = versionBiz.insertVersionWithLogCollect(versionDraft, cluster);
            
        } catch (Exception e) {
            versionBiz.removeById(GlobalConstant.VERSION_TABLE_NAME, versionDraft.getId());
            throw ApiException.wrapMessage(ResultStat.PARAM_ERROR, e.getMessage());
        }
        
        if(CollectionUtils.isNotEmpty(versionDraft.getVolumeDrafts())){
        	// add volume_deploy_map
            for(VolumeDraft vd : versionDraft.getVolumeDrafts()) {
        		if ("PERSISTENTVOLUMECLAIM".equals(vd.getVolumeType().name())) {
        			String storageName = vd.getVolumePVC().getClaimName().split("-pvc")[0];
        			Storage storage = storageBiz.getStorageByName(storageName);
        			VolumeDeployMap volumeDeployMap = new VolumeDeployMap();
        			volumeDeployMap.setDeployId(deployId);
        			volumeDeployMap.setVersionId(versionDraft.getId());
        			volumeDeployMap.setVolumeId(storage.getId());
        			volumeDeployMap.setCreateTime(System.currentTimeMillis());
        			storageBiz.addVolumeVersionMount(volumeDeployMap);
        		}
            }
        }
        return versionId;

    }
    
    @Override
    public HttpResponseTemp<?> sreGetVersionContainerInfo(int deployId, int versionId) throws Exception{
    	Deployment deployment = deploymentBiz.getDeployment(deployId);
    	if (deployment == null) {
    		return ResultStat.PARAM_ERROR.wrap("deploy 不存在");
        }
    	List<Version> versions = versionBiz.getAllVersionByDeployId(deployId);
    	if (versions.size() == 0) {
    		return ResultStat.PARAM_ERROR.wrap("deployid下没有查到任何版本信息");
    	}
    	Version nv = new Version();
    	
    	if (versionId >0) {
    		for(Version version:versions) {
        		if (version.getVersion()==versionId) { 			
        			nv = version;
        			break;
        		}
        	}

    	}else {
    		nv = versions.get(versions.size()-1);
    	}
    	return ResultStat.OK.wrap(nv.getContainerDrafts());
    }
    
    @Override
    public HttpResponseTemp<?> sreGetVersion(int deployId, int versionId) throws Exception {
    	Version version = versionBiz.getVersion(deployId, versionId);
        if (version == null) {
        	return ResultStat.PARAM_ERROR.wrap("version in not exist");
        }
        Deployment deployment = deploymentBiz.getDeployment(deployId);
        if (deployment == null) {
        	return ResultStat.PARAM_ERROR.wrap("deployment is not exist");
        }
        // get clusterName by clusterId
        Cluster cluster = clusterBiz.getById(GlobalConstant.CLUSTER_TABLE_NAME, deployment.getClusterId(), Cluster.class);
        if (cluster == null) {
        	return ResultStat.PARAM_ERROR.wrap("cluster is not exist");
        }
        VersionDraft versionDraft = new VersionDraft(version, deployment, cluster);
        if (version.getVersionType() != VersionType.CUSTOM) {
            DeployResourceHandler deployResourceHandler = ReflectFactory.createDeployResourceHandler(
                    deployment.getDeploymentType().getDeployClassName(), null, deployment);
            VersionString versionString = null;
            if (deployResourceHandler != null) {
                versionString = deployResourceHandler.getVersionString(version, null, null);
            }
            if (versionString != null) {
                versionString.setPodSpecStr(version.getPodSpecStr());

            }
            versionDraft.setVersionString(versionString);
        }

        return ResultStat.OK.wrap(versionDraft);
    }

    @Override
    public VersionDraft getVersion(int deployId, int versionId) throws Exception {
        checkDeployPermit(deployId, OperationType.GET);
        Version version = versionBiz.getVersion(deployId, versionId);
        if (version == null) {
            throw ApiException.wrapResultStat(ResultStat.VERSION_NOT_EXIST);
        }
        Deployment deployment = deploymentBiz.getDeployment(deployId);
        if (deployment == null) {
            throw ApiException.wrapResultStat(ResultStat.DEPLOYMENT_NOT_EXIST);
        }
        // get clusterName by clusterId
        Cluster cluster = clusterBiz.getById(GlobalConstant.CLUSTER_TABLE_NAME, deployment.getClusterId(), Cluster.class);
        if (cluster == null) {
            throw ApiException.wrapResultStat(ResultStat.CLUSTER_NOT_EXIST);
        }
        VersionDraft versionDraft = new VersionDraft(version, deployment, cluster);
        if (version.getVersionType() != VersionType.CUSTOM) {
            DeployResourceHandler deployResourceHandler = ReflectFactory.createDeployResourceHandler(
                    deployment.getDeploymentType().getDeployClassName(), null, deployment);
            VersionString versionString = null;
            if (deployResourceHandler != null) {
                versionString = deployResourceHandler.getVersionString(version, null, null);
            }
            if (versionString != null) {
                versionString.setPodSpecStr(version.getPodSpecStr());

            }
            versionDraft.setVersionString(versionString);
        }

        return versionDraft;
    }
    
    @Override
    public HttpResponseTemp<?> sreListVersion(int deployId,String tag) throws Exception{
    	List<Version> versions = versionBiz.getAllVersionByDeployId(deployId);
        if (versions == null) {
        	return ResultStat.PARAM_ERROR.wrap("does not have version for deploy " + deployId);
        }
        List<VersionInfo> versionInfos = new ArrayList<>(versions.size());
        if (!StringUtils.isEmpty(tag)) {
        	for (Version version : versions) {
        		VersionInfo versionInfo = new VersionInfo(version);
        		if (versionInfo.getTags().contains(tag)) {
        			versionInfos.add(versionInfo);
        			return ResultStat.OK.wrap(versionInfos);
        		}
        	}
        	return ResultStat.OK.wrap(versionInfos);
        }
        for (Version version : versions) {
            VersionInfo versionInfo = new VersionInfo(version);
            versionInfos.add(versionInfo);
        }
        Collections.sort(versionInfos, new Comparator<VersionInfo>() {
            @Override
            public int compare(VersionInfo o1, VersionInfo o2) {
                return ((Long) o2.getVersion()).compareTo(o1.getVersion());
            }
        });

        return ResultStat.OK.wrap(versionInfos);
    }

    @Override
    public List<VersionInfo> listVersion(int deployId) throws Exception {
        checkDeployPermit(deployId, OperationType.GET);
        List<Version> versions = versionBiz.getAllVersionByDeployId(deployId);
        if (versions == null) {
            throw ApiException.wrapMessage(ResultStat.PARAM_ERROR, "does not have version for deploy " + deployId);
        }
        List<VersionInfo> versionInfos = new ArrayList<>(versions.size());
        for (Version version : versions) {
            VersionInfo versionInfo = new VersionInfo(version);
            versionInfos.add(versionInfo);
        }
        Collections.sort(versionInfos, new Comparator<VersionInfo>() {
            @Override
            public int compare(VersionInfo o1, VersionInfo o2) {
                return ((Long) o2.getVersion()).compareTo(o1.getVersion());
            }
        });

        return versionInfos;
    }

    @Override
    public HttpResponseTemp<?> deprecateVersionById(int id) {
        Version version = versionBiz.getById(GlobalConstant.VERSION_TABLE_NAME, id, Version.class);
        if (version == null) {
            throw ApiException.wrapMessage(ResultStat.PARAM_ERROR, "no such version!");
        }
        deprecateVersion(version);
        return ResultStat.OK.wrap(null);
    }

    @Override
    public HttpResponseTemp<?> deprecateVersionByDeployIdAndVersionId(int deployId, int versionId) {
        Version version = versionBiz.getVersion(deployId, versionId);
        if (version == null) {
            throw ApiException.wrapMessage(ResultStat.PARAM_ERROR, "no such version!");
        }
        deprecateVersion(version);
        return ResultStat.OK.wrap(null);
    }
    
    @Override
    public HttpResponseTemp<?> enableVersionById(int id) {
        Version version = versionBiz.getById(GlobalConstant.VERSION_TABLE_NAME, id, Version.class);
        if (version == null) {
            throw ApiException.wrapMessage(ResultStat.PARAM_ERROR, "no such version!");
        }
        enableVersion(version);
        return ResultStat.OK.wrap(null);
    }

    @Override
    public HttpResponseTemp<?> enableVersionByDeployIdAndVersionId(int deployId, int versionId) {
        Version version = versionBiz.getVersion(deployId, versionId);
        if (version == null) {
            throw ApiException.wrapMessage(ResultStat.PARAM_ERROR, "no such version!");
        }
        enableVersion(version);
        return ResultStat.OK.wrap(null);
    }
    
    private void deprecateVersion(Version version) {
        User user = getUser();
        AuthUtil.verify(user.getId(), version.getDeployId(), ResourceType.DEPLOY, OperationType.MODIFY);
        Deployment deployment = deploymentBiz.getDeployment(version.getDeployId());
        if (deployment == null) {
            throw ApiException.wrapResultStat(ResultStat.DEPLOYMENT_NOT_EXIST);
        }
        if (checkDeprecated(deployment, version.getId())) {
            version.setDeprecate(true);
            versionBiz.updateVersion(version);
            configurationBiz.removeConfigurationVersionMapByVersionId(version.getId());
        } else {
            throw ApiException.wrapMessage(ResultStat.CANNOT_DEPRECATE_VERSION, "can't  deprecate current version");
        }
    }
    
    private void enableVersion(Version version) {
        User user = getUser();
        AuthUtil.verify(user.getId(), version.getDeployId(), ResourceType.DEPLOY, OperationType.MODIFY);
        // check config existence first
        checkConfigExistence(version);
        try {
            versionBiz.enableVersion(version);
        } catch (Exception e) {
            configurationBiz.removeConfigurationVersionMapByVersionId(version.getId());
            throw ApiException.wrapMessage(ResultStat.PARAM_ERROR, e.getMessage());
        }
        
    }
    
    void checkDeployPermit(int deployId, OperationType operationType) {
        AuthUtil.verify(CurrentThreadInfo.getUserId(), deployId, ResourceType.DEPLOY, operationType);
    }

    private User getUser() {
        User user = CurrentThreadInfo.getUser();
        if (user == null) {
            throw new PermitException("no user logged in");
        }
        return user;
    }
    
    private void checkConfigExistence(Version version) {
        if (version.getVolumeDrafts() != null && !version.getVolumeDrafts().isEmpty()) {
            for (VolumeDraft volumeDraft : version.getVolumeDrafts()) {
                VolumeConfigMap volumeConfigMap = volumeDraft.getVolumeConfigMap();
                if (VolumeType.CONFIGMAP.equals(volumeDraft.getVolumeType()) && volumeConfigMap != null) {
                    Configuration config = configurationBiz.getConfigurationById(volumeConfigMap.getConfigurationId());
                    if (config == null) {
                        throw ApiException.wrapMessage(ResultStat.CANNOT_ENABLE_VERSION, "Failed to restore, config " + volumeConfigMap.getName() + " have been deleted.");
                    }
                }
            }
        }
    }
    
    private boolean checkDeprecated(Deployment deployment, int deprecatedVersionId) {
        if (!DeploymentStatus.STOP.name().equals(deployment.getState())) {
            RuntimeDriver driver = ClusterRuntimeDriver.getClusterDriver(deployment.getClusterId());
            if (driver == null) {
                throw ApiException.wrapMessage(ResultStat.CLUSTER_NOT_EXIST, " There is no RuntimeDriver for cluster(" + deployment.getClusterId() + ").");
            }
            // get current versions
            List<Version> versions;
            try {
                versions = driver.getCurrnetVersionsByDeployment(deployment);
            } catch (DeploymentEventException e) {
                return false;
            }
            if (versions != null) {
                for (Version ver : versions) {
                    if (ver.getId() == deprecatedVersionId) {
                        return false;
                    }
                }
            } 
        }
        return true;
    }
}